﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using CSGame;

namespace Common
{
    public partial class ChessBox : UserControl
    {
        private List<Figure> _whiteFigures = new List<Figure>();    // белые фигуры
        private List<Figure> _blackFigures = new List<Figure>();    // черные фигуры
        private List<Figure> _selectedFields = new List<Figure>();  // выделенные клетки (куда можно сходить)
        private Player _stepBy;                         // чей ход
        private Player _viewBy = Player.White;          // К кому повернута доска
        private Player _plaingBy = Player.White;        // за кого играем
        private Figure [,] _matrix = new Figure[8,8];   // список позиций - вертикаль, горизонталь
        private Figure _selectedFigure;                 // фигура, которой собираются сходить


        public static Color ClrBattle = Color.FromArgb(100, 255, 50, 50);
        public static Color ClrSelect = Color.FromArgb(100, 50, 255, 50);
        public static Color ClrNothing = Color.Transparent;

        /// <summary>
        /// Событие возникает перед ходом
        /// </summary>
        public event ChessBeforeStepEventHandler BeforeChessGo;
        /// <summary>
        /// Событие возникает после хода
        /// </summary>
        public event ChessAfterStepEventHandler AfterChessGo;


        public ChessBox()
        {
            InitializeComponent();
        }


        #region Свойства

        public Player PlaingBy 
        {
            get { return _plaingBy; }
            set { _plaingBy = value; }
        }


        /// <summary>
        /// С чьей стороны вид на доску
        /// </summary>
        public Player ViewBy
        {
            get { return _viewBy; }
        }

        /// <summary>
        /// список позиций - вертикаль, горизонталь
        /// </summary>
        public Figure[,] Matrix
        {
            get { return _matrix; }
            set { _matrix = value; }
        }


        /// <summary>
        /// Определяет, чей ход в матче
        /// </summary>
        public Player StepBy
        {
            get { return _stepBy; }
            set { _stepBy = value; }
        }


        public PictureBox PicBoard
        {
            get { return picBoard; }
        }
        #endregion


        /// <summary>
        /// Устанавливает на доске начальную позицию
        /// </summary>
        public void StartPosition()
        {
            // очищаем массив позиций
            for (int i = 0; i < 8; i++)
                for (int j = 0; j < 8; j++)
                    _matrix[i, j] = null;//FigureType.Empty;

            for (int i = 0; i < _whiteFigures.Count; i++)
                _whiteFigures[i].Dispose();
            for (int i = 0; i < _blackFigures.Count; i++)
                _blackFigures[i].Dispose();

            lstNotation.Items.Clear();

            _whiteFigures.Clear();
            _blackFigures.Clear();


            for (int i = 0; i < 8; i++)
            {
                _whiteFigures.Add(new Figure(this, Player.White, FigureType.Pawn, i, 1));
                _blackFigures.Add(new Figure(this, Player.Black, FigureType.Pawn, i, 6));
            }
            // белые
            _whiteFigures.Add(new Figure(this, Player.White, FigureType.Rook, 0, 0));
            _whiteFigures.Add(new Figure(this, Player.White, FigureType.Rook, 7, 0));
            _whiteFigures.Add(new Figure(this, Player.White, FigureType.Knight, 1, 0));
            _whiteFigures.Add(new Figure(this, Player.White, FigureType.Knight, 6, 0));
            _whiteFigures.Add(new Figure(this, Player.White, FigureType.Bishop, 2, 0));
            _whiteFigures.Add(new Figure(this, Player.White, FigureType.Bishop, 5, 0));
            _whiteFigures.Add(new Figure(this, Player.White, FigureType.Queen, 3, 0));
            _whiteFigures.Add(new Figure(this, Player.White, FigureType.King, 4, 0));
            // черные
            _blackFigures.Add(new Figure(this, Player.Black, FigureType.Rook, 0, 7));
            _blackFigures.Add(new Figure(this, Player.Black, FigureType.Rook, 7, 7));
            _blackFigures.Add(new Figure(this, Player.Black, FigureType.Knight, 1, 7));
            _blackFigures.Add(new Figure(this, Player.Black, FigureType.Knight, 6, 7));
            _blackFigures.Add(new Figure(this, Player.Black, FigureType.Bishop, 2, 7));
            _blackFigures.Add(new Figure(this, Player.Black, FigureType.Bishop, 5, 7));
            _blackFigures.Add(new Figure(this, Player.Black, FigureType.Queen, 3, 7));
            _blackFigures.Add(new Figure(this, Player.Black, FigureType.King, 4, 7));
            //Refresh();
            _stepBy = Player.White;
            SeeBy(Player.White);
        }


        /// <summary>
        /// Обновить изображение доски и позиции
        /// </summary>
        public new void Refresh()
        {
            if (_viewBy == Player.White) // со стороны белого игрока
            {
                for (int i = 0; i < _whiteFigures.Count; i++)
                {
                    _whiteFigures[i].View.Top = (7 - _whiteFigures[i].Pos.Horizontal) * 35 + 10;
                    _whiteFigures[i].View.Left = (_whiteFigures[i].Pos.Vertical) * 35 + 10;
                }
                for (int i = 0; i < _blackFigures.Count; i++)
                {
                    _blackFigures[i].View.Top = (7 - _blackFigures[i].Pos.Horizontal) * 35 + 10;
                    _blackFigures[i].View.Left = (_blackFigures[i].Pos.Vertical) * 35 + 10;
                }
                // пустые выделенные клетки
                foreach (Figure f in _selectedFields)
                {
                    f.View.Top = (7 - f.Pos.Horizontal) * 35 + 10;
                    f.View.Left = (f.Pos.Vertical) * 35 + 10;
                }
            }
            else // со стороны черного игрока
            {
                for (int i = 0; i < _whiteFigures.Count; i++)
                {
                    _whiteFigures[i].View.Top = (_whiteFigures[i].Pos.Horizontal) * 35 + 10;
                    _whiteFigures[i].View.Left = (7 - _whiteFigures[i].Pos.Vertical) * 35 + 10;
                }
                for (int i = 0; i < _blackFigures.Count; i++)
                {
                    _blackFigures[i].View.Top = (_blackFigures[i].Pos.Horizontal) * 35 + 10;
                    _blackFigures[i].View.Left = (7 - _blackFigures[i].Pos.Vertical) * 35 + 10;
                }
                // пустые выделенные клетки
                foreach (Figure f in _selectedFields)
                {
                    f.View.Top = (f.Pos.Horizontal) * 35 + 10;
                    f.View.Left = (7 - f.Pos.Vertical) * 35 + 10;
                }
            }


        }


        /// <summary>
        /// Сброс выделения
        /// </summary>
        public void NoChecked()
        {
            foreach (Figure f in _whiteFigures)
                f.Checked = false;
            foreach (Figure f in _blackFigures)
                f.Checked = false;

            for (int i = 0; i < _selectedFields.Count; i++) // удаляем выделеие клеток
            {
                _selectedFields[i].Dispose();
                if (/*_matrix[_selectedFields[i].Pos.Vertical, _selectedFields[i].Pos.Horizontal].MyType == FigureType.Empty)*/
                    FieldIsEmpty(_selectedFields[i].Pos.Vertical, _selectedFields[i].Pos.Horizontal))
                    _matrix[_selectedFields[i].Pos.Vertical, _selectedFields[i].Pos.Horizontal] = null;
            }
            _selectedFields.Clear();
            _selectedFigure = null;
            Refresh();
        }


        public void SelectStepFields(Figure f)
        {
            SelectFields(f);    // выделяем куда можно сходить
            CancelFields(f);    // отменяем выделение, если попали под шах
        }


        #region говнокод высшего ранга
        /// <summary>
        /// Отмена выделения клеток, в которые нельзя сходить из-за шаха
        /// </summary>
        private void CancelFields(Figure f)
        {
            List<FigurePosition> mayStep = new List<FigurePosition>();
            List<FigurePosition> ToCancel = new List<FigurePosition>();
            FigurePosition oldPos = f.Pos;
            foreach (Figure fig in _matrix)
                if (fig != null && fig.View.BackColor != ClrNothing && (fig.Pos.Horizontal != oldPos.Horizontal || fig.Pos.Vertical != oldPos.Vertical))
                    mayStep.Add(fig.Pos);

            FigurePosition kingPos;

            foreach (FigurePosition pos in mayStep)
            {
                Figure pr = _matrix[pos.Vertical, pos.Horizontal];// промежуточная
                _matrix[pos.Vertical, pos.Horizontal] = _matrix[oldPos.Vertical, oldPos.Horizontal];
                _matrix[oldPos.Vertical, oldPos.Horizontal] = null;
                NoChecked();
                // выделяем все, куда может сходить противник
                if (f.MyPlayer == Player.White)
                    foreach (Figure opp in _blackFigures) //БЕЛЫЕ
                    {
                        _selectedFigure = opp; 
                        SelectFields(opp);
                    }
                else
                    foreach (Figure opp in _whiteFigures) //ЧЕРНЫЕ
                    {
                        _selectedFigure = opp;
                        SelectFields(opp);
                    }


                if (f.MyType == FigureType.King)
                {
                    kingPos = pos;
                }
                else
                    kingPos = GetFigurePos(FigureType.King, f.MyPlayer); // БЕЛЫЕ


                if (_matrix[kingPos.Vertical, kingPos.Horizontal].View.BackColor == ClrBattle)
                    ToCancel.Add(pos);         // нам шах, надо будет отменить клетку
                _matrix[oldPos.Vertical, oldPos.Horizontal] = _matrix[pos.Vertical, pos.Horizontal];
                _matrix[pos.Vertical, pos.Horizontal] = pr;
            }
            // возвращем все на круги своя
            NoChecked(); 
            _selectedFigure = f;
            foreach (FigurePosition pos in mayStep)
            {
                if (!ToCancel.Contains(pos))
                    AllowField(pos.Vertical, pos.Horizontal);
            }
        }
        #endregion

        /// <summary>
        /// Выделение полей, на которые можно сходить
        /// </summary>
        /// <param name="f">Фигура, которой ходим</param>
        private void SelectFields(Figure f)
        {            
            switch (f.MyType)
            {
                #region Пешка
                case FigureType.Pawn:
                    if (f.MyPlayer == Player.White)
                    {
                        if (f.Pos.Horizontal < 7 && FieldIsEmpty(f.Pos.Vertical, f.Pos.Horizontal + 1))
                        {// вперед
                            _selectedFields.Add(new Figure(this, Player.Speactator, FigureType.Empty, f.Pos.Vertical, f.Pos.Horizontal + 1));
                            if (f.Pos.Horizontal == 1 && FieldIsEmpty(f.Pos.Vertical, f.Pos.Horizontal + 2))
                                _selectedFields.Add(new Figure(this, Player.Speactator, FigureType.Empty, f.Pos.Vertical, f.Pos.Horizontal + 2));
                        }
                        if (f.Pos.Horizontal < 7 && f.Pos.Vertical > 0 && !FieldIsEmpty(f.Pos.Vertical - 1, f.Pos.Horizontal + 1) && _matrix[f.Pos.Vertical - 1, f.Pos.Horizontal + 1].MyPlayer != f.MyPlayer)
                        { // рубим слева
                            _matrix[f.Pos.Vertical - 1, f.Pos.Horizontal + 1].View.BackColor = ClrBattle;
                        }
                        if (f.Pos.Horizontal < 7 && f.Pos.Vertical < 7 && !FieldIsEmpty(f.Pos.Vertical + 1, f.Pos.Horizontal + 1) && _matrix[f.Pos.Vertical + 1, f.Pos.Horizontal + 1].MyPlayer != f.MyPlayer)
                        {// рубим справа
                            _matrix[f.Pos.Vertical + 1, f.Pos.Horizontal + 1].View.BackColor = ClrBattle;
                        }
                    }
                    else // (черная пешка ходит наоборот)
                    {
                        if (f.Pos.Horizontal > 0 && FieldIsEmpty(f.Pos.Vertical, f.Pos.Horizontal - 1))
                        {// вперед
                            _selectedFields.Add(new Figure(this, Player.Speactator, FigureType.Empty, f.Pos.Vertical, f.Pos.Horizontal - 1));
                            if (f.Pos.Horizontal == 6 && FieldIsEmpty(f.Pos.Vertical, f.Pos.Horizontal - 2))
                                _selectedFields.Add(new Figure(this, Player.Speactator, FigureType.Empty, f.Pos.Vertical, f.Pos.Horizontal - 2));
                        }
                        if (f.Pos.Horizontal > 0 && f.Pos.Vertical > 0 && !FieldIsEmpty(f.Pos.Vertical - 1, f.Pos.Horizontal - 1) && _matrix[f.Pos.Vertical - 1, f.Pos.Horizontal - 1].MyPlayer != f.MyPlayer)
                        { // рубим слева
                            _matrix[f.Pos.Vertical - 1, f.Pos.Horizontal - 1].View.BackColor = ClrBattle;
                        }
                        if (f.Pos.Horizontal > 0 && f.Pos.Vertical < 7 && !FieldIsEmpty(f.Pos.Vertical + 1, f.Pos.Horizontal - 1) && _matrix[f.Pos.Vertical + 1, f.Pos.Horizontal - 1].MyPlayer != f.MyPlayer)
                        {// рубим справа
                            _matrix[f.Pos.Vertical + 1, f.Pos.Horizontal - 1].View.BackColor = ClrBattle;
                        }
                    }
                    break;
                #endregion

                #region Ладья
                case FigureType.Rook:
                    AllowLines(f);
                    break;
                #endregion

                #region Слон
                case FigureType.Bishop:
                    AllowDiaganals(f);
                    break;
                #endregion

                #region Ферзь
                case FigureType.Queen:
                    AllowLines(f);
                    AllowDiaganals(f);
                    break;
                #endregion

                #region Король
                case FigureType.King:
                    AllowField(f.Pos.Vertical - 1, f.Pos.Horizontal - 1);
                    AllowField(f.Pos.Vertical - 1, f.Pos.Horizontal);
                    AllowField(f.Pos.Vertical - 1, f.Pos.Horizontal + 1);
                    AllowField(f.Pos.Vertical, f.Pos.Horizontal - 1);
                    AllowField(f.Pos.Vertical, f.Pos.Horizontal + 1);
                    AllowField(f.Pos.Vertical + 1, f.Pos.Horizontal - 1);
                    AllowField(f.Pos.Vertical + 1, f.Pos.Horizontal);
                    AllowField(f.Pos.Vertical + 1, f.Pos.Horizontal + 1);
                    // рокировка
                    if (f.MyPlayer == Player.White && f.Pos.Vertical == 4 && f.Pos.Horizontal == 0)
                    { // если белый король на своем месте
                        if (FieldIsEmpty(5, 0) && FieldIsEmpty(6, 0)
                            && _matrix[7, 0] != null
                            && _matrix[7, 0].MyPlayer == Player.White
                            && _matrix[7, 0].MyType == FigureType.Rook)
                            AllowField(6, 0); // в короткую сторону
                        if (FieldIsEmpty(1, 0) && FieldIsEmpty(2, 0) && FieldIsEmpty(3, 0)
                            && _matrix[0, 0] != null
                            && _matrix[0, 0].MyPlayer == Player.White
                            && _matrix[0, 0].MyType == FigureType.Rook)
                            AllowField(2, 0); // в длинную сторону
                    }
                    if (f.MyPlayer == Player.Black && f.Pos.Vertical == 4 && f.Pos.Horizontal == 7)
                    { // если черный король на своем месте
                        if (FieldIsEmpty(5, 7) && FieldIsEmpty(6, 7)
                            && _matrix[7, 7] != null
                            && _matrix[7, 7].MyPlayer == Player.Black
                            && _matrix[7, 7].MyType == FigureType.Rook)
                            AllowField(6, 7); // в короткую сторону
                        if (FieldIsEmpty(1, 7) && FieldIsEmpty(2, 7) && FieldIsEmpty(3, 7)
                            && _matrix[0, 7] != null
                            && _matrix[0, 7].MyPlayer == Player.Black
                            && _matrix[0, 7].MyType == FigureType.Rook)
                            AllowField(2, 7); // в длинную сторону
                    }
                    break;
                #endregion

                #region Конь
                case FigureType.Knight:
                    AllowField(f.Pos.Vertical - 2, f.Pos.Horizontal + 1);
                    AllowField(f.Pos.Vertical - 2, f.Pos.Horizontal - 1);
                    AllowField(f.Pos.Vertical + 2, f.Pos.Horizontal + 1);
                    AllowField(f.Pos.Vertical + 2, f.Pos.Horizontal - 1);
                    AllowField(f.Pos.Vertical - 1, f.Pos.Horizontal + 2);
                    AllowField(f.Pos.Vertical + 1, f.Pos.Horizontal + 2);
                    AllowField(f.Pos.Vertical - 1, f.Pos.Horizontal - 2);
                    AllowField(f.Pos.Vertical + 1, f.Pos.Horizontal - 2);
                    break;
                #endregion
            }
        }


        #region вспомогательное

        #region Проверка на пустоту

        /// <summary>
        /// Проверяет клетку на отсутствие фигур
        /// </summary>
        /// <param name="pos">Клетка</param>
        private bool FieldIsEmpty(FigurePosition pos)
        {
            return (_matrix[pos.Vertical, pos.Horizontal] == null || _matrix[pos.Vertical, pos.Horizontal].MyType == FigureType.Empty);
        }

        /// <summary>
        /// Проверяет клетку на отсутствие фигур
        /// </summary>
        /// <param name="v">Вертикаль клетки</param>
        /// <param name="h">Горизонталь клетки</param>
        private bool FieldIsEmpty(int v, int h)
        {
            return (_matrix[v, h] == null || _matrix[v, h].MyType == FigureType.Empty);
        }

        #endregion

        #region клетка
        /// <summary>
        /// Разрешает фигуре переход в клетку
        /// </summary>
        /// <param name="f">Фигура</param>
        /// <param name="v">Вертикаль клетки</param>
        /// <param name="h">Горизонталь клетки</param>
        private void AllowField(int v, int h)
        {
            if (v >= 0 && v < 8 && h < 8 && h >= 0)
                if (FieldIsEmpty(v, h)) // если в клетке никого нет
                    _selectedFields.Add(new Figure(this, Player.Speactator, FigureType.Empty, v, h));
                else
                    if (_matrix[v, h].MyPlayer != _selectedFigure.MyPlayer) // если в клетке противник
                        _matrix[v, h].View.BackColor = ClrBattle;
        }
        #endregion

        #region прямые
        /// <summary>
        /// Разрешает фигуре ходить по прямым линиям
        /// </summary>
        /// <param name="f">Фигура</param>
        private void AllowLines(Figure f)
        {
            // направо
            for (int i = f.Pos.Vertical + 1; i < 8; i++)
                if (FieldIsEmpty(i, f.Pos.Horizontal))
                    _selectedFields.Add(new Figure(this, Player.Speactator, FigureType.Empty, i, f.Pos.Horizontal));
                else
                {
                    if (_matrix[i, f.Pos.Horizontal].MyPlayer != f.MyPlayer)
                        _matrix[i, f.Pos.Horizontal].View.BackColor = ClrBattle;
                    break;
                }
            // налево
            for (int i = f.Pos.Vertical - 1; i >= 0; i--)
                if (FieldIsEmpty(i, f.Pos.Horizontal))
                    _selectedFields.Add(new Figure(this, Player.Speactator, FigureType.Empty, i, f.Pos.Horizontal));
                else
                {
                    if (_matrix[i, f.Pos.Horizontal].MyPlayer != f.MyPlayer)
                        _matrix[i, f.Pos.Horizontal].View.BackColor = ClrBattle;
                    break;
                }
            // вверх
            for (int i = f.Pos.Horizontal + 1; i < 8; i++)
                if (FieldIsEmpty(f.Pos.Vertical, i))
                    _selectedFields.Add(new Figure(this, Player.Speactator, FigureType.Empty, f.Pos.Vertical, i));
                else
                {
                    if (_matrix[f.Pos.Vertical, i].MyPlayer != f.MyPlayer)
                        _matrix[f.Pos.Vertical, i].View.BackColor = ClrBattle;
                    break;
                }
            // вниз
            for (int i = f.Pos.Horizontal - 1; i >= 0; i--)
                if (FieldIsEmpty(f.Pos.Vertical, i))
                    _selectedFields.Add(new Figure(this, Player.Speactator, FigureType.Empty, f.Pos.Vertical, i));
                else
                {
                    if (_matrix[f.Pos.Vertical, i].MyPlayer != f.MyPlayer)
                        _matrix[f.Pos.Vertical, i].View.BackColor = ClrBattle;
                    break;
                }
        }
        #endregion

        #region диагонали
        /// <summary>
        /// Разрешает фигуре ходить по диагоналям
        /// </summary>
        /// <param name="f">Фигура</param>
        private void AllowDiaganals(Figure f)
        {
            // направо вверх
            for (int i = 1; i < 8; i++)
            {
                if (f.Pos.Vertical + i > 7 || f.Pos.Horizontal + i > 7)
                    break;
                if (FieldIsEmpty(f.Pos.Vertical + i, f.Pos.Horizontal + i))
                    _selectedFields.Add(new Figure(this, Player.Speactator, FigureType.Empty, f.Pos.Vertical + i, f.Pos.Horizontal + i));
                else
                {
                    if (_matrix[f.Pos.Vertical + i, f.Pos.Horizontal + i].MyPlayer != f.MyPlayer)
                        _matrix[f.Pos.Vertical + i, f.Pos.Horizontal + i].View.BackColor = ClrBattle;
                    break;
                }
            }
            // налево вниз
            for (int i = 1; i < 8; i++)
            {
                if (f.Pos.Vertical - i < 0 || f.Pos.Horizontal - i < 0)
                    break;
                if (FieldIsEmpty(f.Pos.Vertical - i, f.Pos.Horizontal - i))
                    _selectedFields.Add(new Figure(this, Player.Speactator, FigureType.Empty, f.Pos.Vertical - i, f.Pos.Horizontal - i));
                else
                {
                    if (_matrix[f.Pos.Vertical - i, f.Pos.Horizontal - i].MyPlayer != f.MyPlayer)
                        _matrix[f.Pos.Vertical - i, f.Pos.Horizontal - i].View.BackColor = ClrBattle;
                    break;
                }
            }
            // направо вниз
            for (int i = 1; i < 8; i++)
            {
                if (f.Pos.Vertical + i > 7 || f.Pos.Horizontal - i < 0)
                    break;
                if (FieldIsEmpty(f.Pos.Vertical + i, f.Pos.Horizontal - i))
                    _selectedFields.Add(new Figure(this, Player.Speactator, FigureType.Empty, f.Pos.Vertical + i, f.Pos.Horizontal - i));
                else
                {
                    if (_matrix[f.Pos.Vertical + i, f.Pos.Horizontal - i].MyPlayer != f.MyPlayer)
                        _matrix[f.Pos.Vertical + i, f.Pos.Horizontal - i].View.BackColor = ClrBattle;
                    break;
                }
            }
            // налево вверх
            for (int i = 1; i < 8; i++)
            {
                if (f.Pos.Vertical - i < 0 || f.Pos.Horizontal + i > 7)
                    break;
                if (FieldIsEmpty(f.Pos.Vertical - i, f.Pos.Horizontal + i))
                    _selectedFields.Add(new Figure(this, Player.Speactator, FigureType.Empty, f.Pos.Vertical - i, f.Pos.Horizontal + i));
                else
                {
                    if (_matrix[f.Pos.Vertical - i, f.Pos.Horizontal + i].MyPlayer != f.MyPlayer)
                        _matrix[f.Pos.Vertical - i, f.Pos.Horizontal + i].View.BackColor = ClrBattle;
                    break;
                }
            }
        }
        #endregion

        #endregion


        #region Перегрузки метода DoStep (для совершения хода)

        /// <summary>
        /// Делаем ход
        /// </summary>
        /// <param name="f">Фигура (или пустая клетка) на которую надо встать</param>
        /// <returns>Возвращает нотацию хода</returns>
        public string DoStep(Figure f)
        {
            if (_selectedFigure == null)
                throw new ChessException("Не выбрана фигура");

            bool danger = false;
            string notation = _selectedFigure.Pos.ToString(); // нотация

            if (_matrix[f.Pos.Vertical, f.Pos.Horizontal].MyType != FigureType.Empty)
            {
                _matrix[f.Pos.Vertical, f.Pos.Horizontal].Dispose(); // что-то срубили
                notation += ":";
            }
            else
                notation += "-";

            
            notation += f.Pos.ToString();

            #region рокировка
            // на самом деле можно написать метод, а не два раза один и тот же код
            #region белые 
            if (_selectedFigure.MyType == FigureType.King
                && _selectedFigure.MyPlayer == Player.White
                && _selectedFigure.Pos.Vertical == 4
                && _selectedFigure.Pos.Horizontal == 0) // белые
            {
                if (f.Pos.Vertical == 6 && f.Pos.Horizontal == 0) // в короткую сторону
                {
                    notation = "0-0";
                    _matrix[5, 0] = _matrix[7, 0]; // переставляем ладью
                    _matrix[7, 0] = null;
                    _whiteFigures[_whiteFigures.IndexOf(_matrix[5, 0])].Pos = new FigurePosition(5, 0);
                }
                else if (f.Pos.Vertical == 2 && f.Pos.Horizontal == 0) // в длинную сторону
                {
                    notation = "0-0-0";
                    _matrix[3, 0] = _matrix[0, 0]; // переставляем ладью
                    _matrix[0, 0] = null;
                    _whiteFigures[_whiteFigures.IndexOf(_matrix[3, 0])].Pos = new FigurePosition(3, 0);
                }
            }
            #endregion

            #region черные
            if (_selectedFigure.MyType == FigureType.King
                && _selectedFigure.MyPlayer == Player.Black
                && _selectedFigure.Pos.Vertical == 4
                && _selectedFigure.Pos.Horizontal == 7) // белые
            {
                if (f.Pos.Vertical == 6 && f.Pos.Horizontal == 7) // в короткую сторону
                {
                    notation = "0-0";
                    _matrix[5, 7] = _matrix[7, 7]; // переставляем ладью
                    _matrix[7, 7] = null;
                    _whiteFigures[_whiteFigures.IndexOf(_matrix[5, 7])].Pos = new FigurePosition(5, 7);
                }
                else if (f.Pos.Vertical == 2 && f.Pos.Horizontal == 7) // в длинную сторону
                {
                    notation = "0-0-0";
                    _matrix[3, 7] = _matrix[0, 7]; // переставляем ладью
                    _matrix[0, 7] = null;
                    _whiteFigures[_whiteFigures.IndexOf(_matrix[3, 7])].Pos = new FigurePosition(3, 7);
                }
            }
            #endregion

            #endregion

            // переставляем в матрице позиций
            _matrix[f.Pos.Vertical, f.Pos.Horizontal] = _selectedFigure;
            _matrix[_selectedFigure.Pos.Vertical, _selectedFigure.Pos.Horizontal] = null;

            // переставляем в списках
            _selectedFigure.Pos = f.Pos;


            // если пешка дошла до конца
            if ((_selectedFigure.MyType == FigureType.Pawn && _selectedFigure.MyPlayer == Player.White && f.Pos.Horizontal == 7)
                || (_selectedFigure.MyType == FigureType.Pawn && _selectedFigure.MyPlayer == Player.Black && f.Pos.Horizontal == 0))
            {
                MessageBox.Show("Пешка уже дошла до конца, а я так и не дописал метод...", "Печалька", MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }

           
            #region Определение шаха
            if (_stepBy == Player.White)
            {
                foreach (Figure fig in _whiteFigures)
                { // выделяем все возможное
                    SelectFields(fig);
                }
                FigurePosition kp = GetFigurePos(FigureType.King, Player.Black); // вражеский король!
                if (_matrix[kp.Vertical, kp.Horizontal].View.BackColor == ClrBattle) // АХАХАХА
                {
                    notation += "+";
                    danger = true;
                }
            }
            else // ходит черный
            {
                foreach (Figure fig in _blackFigures)
                { // выделяем все возможное
                    SelectFields(fig);
                }
                FigurePosition kp = GetFigurePos(FigureType.King, Player.White); // вражеский король!
                if (_matrix[kp.Vertical, kp.Horizontal].View.BackColor == ClrBattle) // АХАХАХА
                {
                    notation += "+";
                    danger = true;
                }
            }
            #endregion


            // делаем запись
            if (_selectedFigure.MyPlayer == Player.White)
                lstNotation.Items.Add(notation);
            else
            {
                notation = lstNotation.Items[lstNotation.Items.Count - 1] + "  " + notation;
                lstNotation.Items.RemoveAt(lstNotation.Items.Count - 1);
                lstNotation.Items.Add(notation);
            }

            ChessAfterStepEventArgs e = new ChessAfterStepEventArgs(new ChessStep(_selectedFigure.Pos, f.Pos), notation, danger);

            NoChecked(); // отменяем выделение


            // смена хода
            if (StepBy == Player.Black)
                StepBy = Player.White;
            else
                StepBy = Player.Black;

            // запускаем событие
            AfterStep(e);
            return notation;
        }




        /// <summary>
        /// Делаем ход с одной клетки на другую
        /// </summary>
        /// <param name="start">Откуда берем фигуру</param>
        /// <param name="finish">Куда ставим фигуру</param>
        public string DoStep(FigurePosition start, FigurePosition finish)
        {
            if (start.Horizontal < 0 || start.Horizontal > 7 || start.Vertical < 0 || start.Horizontal > 7)
                throw new ChessException("Попытка взять фигуру из-за пределов доски");
            if (_matrix[start.Vertical, start.Horizontal] == null)
                throw new ChessException("Попытка сходить пустой клеткой");
            _selectedFigure = _matrix[start.Vertical, start.Horizontal];
            return DoStep(finish);
        }


        /// <summary>
        ///  Делаем ход выбранной фигурой в клетку
        /// </summary>
        /// <param name="pos">Клетка, в которую ходим</param>
        public string DoStep(FigurePosition pos)
        {
            if (pos.Horizontal < 0 || pos.Horizontal > 7 || pos.Vertical < 0 || pos.Horizontal > 7)
                throw new ChessException("Попытка поставить фигуру за пределы доски");
            if (_selectedFigure == null)
                throw new ChessException("Не выбрана фигура");
            AllowField(pos.Vertical, pos.Horizontal);
            return DoStep(_matrix[pos.Vertical, pos.Horizontal]);
        }


        /// <summary>
        /// Делаем ход
        /// </summary>
        /// <param name="step">Ход</param>
        public string DoStep(ChessStep step)
        {
            return DoStep(step.Start, step.Finish);
        }


        #endregion


        /// <summary>
        /// Возвращает позицию фигуры по ее характеристике
        /// </summary>
        /// <param name="ft">Тип фигуры</param>
        /// <param name="col">Цвет фигуры</param>
        private FigurePosition GetFigurePos(FigureType ft, Player col)
        {
            List<Figure> lst;
            if (col == Player.White)
                lst = _whiteFigures;
            else
                lst = _blackFigures;
            foreach (Figure f in lst)
                if (f.MyType == ft)
                    return f.Pos;
            return new FigurePosition(); // не нашли фигуру
        }


        #region Инициаторы событий

        /// <summary>
        /// Инициатор события, возникающего перед ходм
        /// </summary>
        /// <param name="e"></param>
        protected virtual void BeforeStep(ChessBeforeStepEventArgs e)
        {
            if (BeforeChessGo != null)
            {
                BeforeChessGo(this, e);
            }
        }

        /// <summary>
        /// Инициатор события после хода
        /// </summary>
        /// <param name="e"></param>
        protected virtual void AfterStep(ChessAfterStepEventArgs e)
        {
            if (AfterChessGo != null)
            {
                AfterChessGo(this, e);
            }
        }
        #endregion

        /// <summary>
        /// Выделение одной фигуры
        /// </summary>
        /// <param name="f">Фигура</param>
        public void SelectFigure(Figure f)
        {
            bool ch = f.Checked;
            NoChecked();
            if (!ch)
                _selectedFigure = f; // сохраняем ссылку на выбранную фигуру
            f.Checked = !ch; // меняем выделение (подсветка - в свойстве)
        }



        /// <summary>
        /// Устанавливает точку зрения на доску
        /// </summary>
        /// <param name="p">Игрок, от которого смотрим</param>
        public void SeeBy(Player p)
        {
            if (p != _viewBy)
            {
                _viewBy = p;
                picBoard.Image.RotateFlip(RotateFlipType.Rotate180FlipNone);
                picBoard.Refresh();
                this.Refresh();
            }
        }


        /// <summary>
        /// Готовы сделать ход
        /// </summary>
        /// <param name="f">Фигура, которой ходим</param>
        internal void PrepareStep(Figure f)
        {
            if (_selectedFigure == null)
                throw new ChessException("Не выбрана фигура");

            // запускаем событие
            ChessBeforeStepEventArgs e = new ChessBeforeStepEventArgs(new ChessStep(_selectedFigure.Pos, f.Pos));
            BeforeStep(e);
        }
    }
}
